package com.pangu;

import com.pangu.bean.ModuleConfig;

import java.lang.reflect.Constructor;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 模块管理
 * <p/>
 * Created by cxlin
 */
public class ModuleManager {

    public static final String TAG = ModuleManager.class.getSimpleName();

    private AMApplication imContext;

    // 模块实现列表
    private Map<String, Object> moduleMap = new HashMap<String, Object>();

    // 用于缓存构造同步
    private ReadWriteLock rwlock = new ReentrantReadWriteLock(false);

    public ModuleManager(AMApplication amApplication) {
        this.imContext = amApplication;
    }

    /**
     * 这里只返回已经初始化的模块
     *
     * @return
     */
    public Map<String, AModule> getModuleMapView() {
        Map<String, AModule> moduleViewMap = new HashMap<String, AModule>();
        for (Entry<String, Object> entry : moduleMap.entrySet()) {
            if (entry.getValue() instanceof AModule) {
                moduleViewMap.put(entry.getKey(), (AModule) entry.getValue());
            }
        }
        return moduleViewMap;
    }

    /**
     * 注册模块
     *
     * @param moduleMark 模块标示
     */
    public void registerModule(String moduleMark, ModuleConfig mConfig) {
        rwlock.writeLock().lock();
        try {
            moduleMap.put(moduleMark, mConfig);
            // 如果没有延迟加载，则直接初始化模块
            if (!mConfig.isDelay()) {
                imContext.getSubModule(moduleMark);
            }

        } catch (Exception e) {
            e.printStackTrace();

        } finally {
            rwlock.writeLock().unlock();
        }

    }

    /**
     * 取消模块注册
     *
     * @param moduleMark 模块标示
     */
    public void unregisterModule(String moduleMark) {
        rwlock.writeLock().lock();
        try {
            Object obj = moduleMap.remove(moduleMark);
            if (obj instanceof AModule) {
                ((AModule) obj).releaseModule();
            }

        } catch (Exception e) {
            e.printStackTrace();

        } finally {
            rwlock.writeLock().unlock();
        }

    }

    /**
     * 释放所有模块，主要用于退出时资源释放
     */
    public void releaseModules() {
        rwlock.writeLock().lock();
        try {
            Collection cacheData = moduleMap.values();
            for (Object obj : cacheData) {
                if (obj instanceof AModule) {
                    ((AModule) obj).releaseModule();
                }
            }

        } catch (Exception e) {
            e.printStackTrace();

        } finally {
            rwlock.writeLock().unlock();
        }

    }

    /**
     * 获得模块
     *
     * @param moduleMark 模块标示
     */
    public AModule getModule(String moduleMark) {
        rwlock.readLock().lock();
        AModule module = null;
        try {
            Object obj = moduleMap.get(moduleMark);
            if (obj != null) {
                if (obj instanceof AModule) {
                    module = (AModule) obj;

                } else if (obj instanceof ModuleConfig) {
                    rwlock.readLock().unlock();
                    rwlock.writeLock().lock();
                    try {
                        // 加载当前模块及其依赖模块
                        module = loadModAndDependMods(moduleMark);

                    } catch (Exception e) {
                        e.printStackTrace();

                    } finally {
                        rwlock.readLock().lock();
                        rwlock.writeLock().unlock();
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();

        } finally {
            rwlock.readLock().unlock();
        }

        return module;
    }

    /**
     * 加载当前模块及其依赖的模块
     * 如果已存在模块及认为其所依赖的模块都已加载了
     *
     * @param moduleMark 当前模块的模块名称
     * @return 当前模块
     */
    private AModule loadModAndDependMods(String moduleMark) throws Exception {
        Object obj = moduleMap.get(moduleMark);
        AModule module = null;
        if (obj != null) {
            if (obj instanceof AModule) {// 当加载当前模块时，这里要多次判断，避免再次进入的时候已经被初始化过了。
                module = (AModule) obj;

            } else if (obj instanceof ModuleConfig) {
                // 加载依赖模块
                ModuleConfig mConfig = (ModuleConfig) obj;
                for (String dependMark : mConfig.getDependModules()) {
                    loadModAndDependMods(dependMark);
                }

                // 加载模块
                module = doBuildModule(imContext, moduleMark, mConfig.getClassName());
                if (module != null) {
                    moduleMap.put(moduleMark, module);// 把加载的模块存到模块映射中
                }
            }
        }

        return module;
    }

    /**
     * 创建模块
     *
     * @param amApplication
     * @param key           缓存标示
     * @param className     缓存实现完整类名
     * @return
     */
    private AModule doBuildModule(AMApplication amApplication, String key, String className) throws Exception {
        Constructor con = Class.forName(className).getConstructor(AMApplication.class, String.class);
        AModule module = (AModule) con.newInstance(amApplication, key);
        // 创建模块
        module.buildModule();

        return module;
    }

}
